//
//  AI.m
//  Maciago
//
//  Created by mmarcos on Sat Nov 03 2001.
//  Copyright (c) 2001 __MyCompanyName__. All rights reserved.
//

#import "AI.h"
#import "board_data.h"

@implementation AI

+(int)boardValue:(struct board_data *)data turn:(int)turn
{
    //register int x;
    //register int y;
    int val1 = 0, val2 = 0;
    int boardSize = data->size;
	int nWhites = numberOfWhites(data);
	int nBlacks = numberOfBlacks(data);
	
	if (((boardSize*boardSize) - (nWhites + nBlacks)) < 10)
	{
		data->wStables = data->bStables = 0;
		nWhites *= 10;
		nBlacks *= 10;
	}
	else
	{
		markStablePieces (data);
	}
	
	if (!nWhites)
	{
		nBlacks += 10000;
	}
	if (!nBlacks)
	{
		nWhites += 10000;
	}
	
   
	if (turn & kWhitePiece)
    {
        //val1 = (data->wStables*(boardSize-6)) + nWhites;
        //val2 = (data->bStables*(boardSize-6)) + nBlacks;
		val1 = (data->wStables+1)*nWhites;
		val2 = (data->bStables+1)*nBlacks;
    }
    else
    {
        //val1 = (data->bStables*(boardSize-6)) + nBlacks;
        //val2 = (data->wStables*(boardSize-6)) + nWhites;
        val1 = (data->bStables+1)*nBlacks;
        val2 = (data->wStables+1)*nWhites;
    }
    
//	if ((val1 - val2) > 0)
		return (val1 - val2);
//	return 0;
}


+(struct board_array *)makeBoards:(struct board_data *)data turn:(int)turn
{
    struct board_array *array;
    struct board_data *newBoard;
    register int x;
    register int y;
    int boardSize = data->size;
    
    array = board_array_create ();
    newBoard = board_data_copy (data);
    for (y = 0; y < boardSize; ++y)
    {
	for (x = 0; x < boardSize; ++x)
	{

	    if (checkMove (newBoard, x, y, turn, true))
	    {
                // set data needed for evaluate
		newBoard->aux_x = x;
		newBoard->aux_y = y;
		board_array_add (array, newBoard);
		newBoard = board_data_copy (data);
	    }
	}
    }
    if (newBoard)
	board_data_dispose (newBoard);
    if (board_array_count (array))
	return array;
    
    board_array_dispose (array);
    return nil;
}


+(int)ABnegaSearch:(BoardData *)data turn:(int)turn 
	 depth:(int)depth outX:(int *)outX outY:(int *)outY
{
    return [self ABnegaSearchInternal:[data board_data] turn:turn 
	 depth:depth alpha:-10000 beta:10000 
	 outX:outX outY:outY];

}

+(int)ABnegaSearchInternal:(struct board_data *)data turn:(int)turn 
	 depth:(int)depth alpha:(int)alpha beta:(int)beta 
	 outX:(int *)outX outY:(int *)outY
{
    int tempX, tempY, 
	i, temp;
    struct board_array *array = [self makeBoards:data turn:turn];
    struct board_data *board_temp;
    int arrayCount = board_array_count (array);
    
    
    if (array != nil && depth)
    {
	for (i = 0; (i < arrayCount) && (alpha < beta); ++i)
	{
		temp = -([self ABnegaSearchInternal:board_array_index (array, i)
		    turn:getOpponent (turn)
		    depth:depth-1
		    alpha:-beta beta:-alpha
		    outX:&tempX outY:&tempY]);
	    
	    if (temp > alpha)
	    {
		board_temp = board_array_index (array, i);
                *outX = board_temp->aux_x;
                *outY = board_temp->aux_y;
		alpha = temp;
	    }
	}
    }
    else
    {
        *outX = data->aux_x;
        *outY = data->aux_y;
        alpha = /*(arrayCount*2) +*/ [self boardValue:data turn:turn];
    }

//    NSLog (@"value:%d level:%d x:%d y:%d", val, depth, *outX, *outY);
    if (array)
	board_array_dispose (array);
    return alpha;
}

+ (BOOL) makeRandomMove:(struct board_data *)data turn:(int)turn
                          outX:(int *)outX outY:(int *)outY
{
    struct board_array *array = [self makeBoards:data turn:turn];
    int randomPos = clock () % board_array_count(array);
    
    struct board_data *randomBoard = board_array_index (array, randomPos);
    
    *outX = randomBoard->aux_x;
    *outY = randomBoard->aux_y;

    if (array)
        board_array_dispose (array);
    
    return YES;
}

+ (BOOL) makeComputerMove:(BoardData *)bd turn:(int)turn
	       level:(int)level
{
    BOOL moveIsPossible = NO;
    struct board_data *data;
    int x = -1;
	int y = -1;
	int npieces = [bd numberOfWhites] + [bd numberOfBlacks];
    
    [bd retain];
    data = [bd board_data];
    
	if (markLegalMoves(data, turn, false))
    {
        if ((npieces > 9) && level)
        {
            [self ABnegaSearch:bd turn:turn
                depth:level outX:&x outY:&y];
        }
        else
        {
            [self makeRandomMove:data turn:turn
                outX:&x outY:&y];
        }

	if (x != -1)
	{
	    checkMove (data, x, y, turn, true);
            moveIsPossible = YES;
	}
    }
        
    if (!markLegalMoves (data, getOpponent(turn), true))
	markLegalMoves (data, turn, true);

    [bd set_board_data: data];
    [bd release];
    board_data_dispose (data);
    return moveIsPossible;
}


@end
